package com.himaci.framework.helper;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import java.util.ArrayList;

/**
 * Kelas yang digunakan untuk animasi splash, dapat berupa image maupun teks.
 * Kita bisa mendapatkan gambar dan opacity yang tepat dari suatu waktu.
 * 
 * @author XNPSDN
 */
public class SplashAnimator {

    private ArrayList<SplashImage> imageList;
    private ArrayList<SplashText> textList;

    private class SplashItem {

        public static final float DEFAULT_FADETIME = 0.5f;
        float startTime;
        float fadeInDuration;
        float imageDuration;
        float fadeOutDuration;
        float endTime;

        public SplashItem(float startTime, float fadeInDuration, float imageDuration, float fadeOutDuration) {
            this.startTime = startTime;
            this.fadeInDuration = fadeInDuration;
            this.imageDuration = imageDuration;
            this.fadeOutDuration = fadeOutDuration;
            this.endTime = startTime + fadeInDuration + imageDuration + fadeOutDuration;
        }
    }

    private class SplashImage extends SplashItem {

        TextureRegion image;

        public SplashImage(TextureRegion image, float startTime, float fadeIn, float imageDuration, float fadeOut) {
            super(startTime, fadeIn, imageDuration, fadeOut);
            this.image = image;
        }
    }

    private class SplashText extends SplashItem {

        String text;
        Color color;

        public SplashText(String text, Color color, float startTime, float fadeIn, float imageDuration, float fadeOut) {
            super(startTime, fadeIn, imageDuration, fadeOut);
            this.text = text;
            this.color = color;
        }
    }

    /**
     * Membuat objek SplashAnimator baru.
     */
    public SplashAnimator() {
        imageList = new ArrayList<>();
        textList = new ArrayList<>();
    }

    /**
     * Menambahkan gambar dalam SplashAnimator pada bagian akhir list gambar.
     * 
     * @param image Gambar masukan
     * @param duration Waktu yang diinginkan mulai dari awal fadein sampai akhir fadeout
     * @return True jika berhasil dan False jika gagal
     */
    public boolean addImage(TextureRegion image, float duration) {
        if (duration > 2 * SplashItem.DEFAULT_FADETIME) {
            float insertTime = getLastImageEndTime();
            imageList.add(new SplashImage(image, insertTime, SplashItem.DEFAULT_FADETIME, duration - (2 * SplashItem.DEFAULT_FADETIME), SplashItem.DEFAULT_FADETIME));
            return true;
        }
        return false;
    }

    /**
     * Menambahkan gambar dalam SplashAnimator pada saat startTime
     * 
     * @param image Gambar masukan
     * @param startTime Waktu mulai muncul
     * @param duration Waktu yang diinginkan mulai dari awal fadein sampai akhir fadeout
     * @return True jika berhasil dan False jika gagal
     */
    public boolean addImage(TextureRegion image, float startTime, float duration) {
        if (duration > 2 * SplashItem.DEFAULT_FADETIME && isImageOver(startTime)) {
            imageList.add(new SplashImage(image, startTime, SplashItem.DEFAULT_FADETIME, duration - (2 * SplashItem.DEFAULT_FADETIME), SplashItem.DEFAULT_FADETIME));
            return true;
        }
        return false;
    }

    /**
     * Menambahkan gambar dalam SplashAnimator pada saat startTime
     * 
     * @param image Gambar masukan
     * @param startTime Waktu mulai muncul
     * @param fadeIn Durasi fadein
     * @param imageDuration Durasi gambar full ditampilkan
     * @param fadeOut Durasi fadeout
     * @return True jika berhasil dan False jika gagal
     */
    public boolean addImage(TextureRegion image, float startTime, float fadeIn, float imageDuration, float fadeOut) {
        if (isImageOver(startTime)) {
            imageList.add(new SplashImage(image, startTime, fadeIn, imageDuration, fadeOut));
            return true;
        }
        return false;
    }

    /**
     * Menambahkan teks dalam SplashAnimator pada bagian akhir list teks.
     * 
     * @param text Teks masukan
     * @param color Warna dari teks
     * @param duration Waktu yang diinginkan mulai dari awal fadein sampai akhir fadeout
     * @return True jika berhasil dan False jika gagal
     */
    public boolean addText(String text, Color color, float duration) {
        if (duration > 2 * SplashItem.DEFAULT_FADETIME) {
            float insertTime = getLastTextEndTime();
            textList.add(new SplashText(text, color, insertTime, SplashItem.DEFAULT_FADETIME, duration - (2 * SplashItem.DEFAULT_FADETIME), SplashItem.DEFAULT_FADETIME));
            return true;
        }
        return false;
    }

    /**
     * Menambahkan teks dalam SplashAnimator pada saat startTime
     * 
     * @param text Teks masukan
     * @param color Warna dari teks
     * @param startTime Waktu mulai muncul
     * @param duration Waktu yang diinginkan mulai dari awal fadein sampai akhir fadeout
     * @return True jika berhasil dan False jika gagal
     */
    public boolean addText(String text, Color color, float startTime, float duration) {
        if (duration > 2 * SplashItem.DEFAULT_FADETIME && isTextOver(startTime)) {
            textList.add(new SplashText(text, color, startTime, SplashItem.DEFAULT_FADETIME, duration - (2 * SplashItem.DEFAULT_FADETIME), SplashItem.DEFAULT_FADETIME));
            return true;
        }
        return false;
    }

    /**
     * Menambahkan text dalam SplashAnimator pada saat startTime
     * 
     * @param text Teks masukan
     * @param color Warna dari teks
     * @param startTime Waktu mulai muncul
     * @param fadeIn Durasi fadein
     * @param textDuration Durasi teks full ditampilkan
     * @param fadeOut Durasi fadeout
     * @return True jika berhasil dan False jika gagal
     */
    public boolean addText(String text, Color color, float startTime, float fadeIn, float textDuration, float fadeOut) {
        if (isTextOver(startTime)) {
            textList.add(new SplashText(text, color, startTime, fadeIn, textDuration, fadeOut));
            return true;
        }
        return false;
    }

    /**
     * Mendapatkan waktu terakhir gambar muncul.
     * 
     * @return Waktu terakhir gambar muncul
     */
    public float getLastImageEndTime() {
        return imageList.isEmpty() ? 0 : imageList.get(imageList.size() - 1).endTime;
    }

    /**
     * Mendapatkan waktu terakhir teks muncul.
     * 
     * @return Waktu terakhir teks muncul
     */
    public float getLastTextEndTime() {
        return textList.isEmpty() ? 0 : textList.get(textList.size() - 1).endTime;
    }

    /**
     * Cek apakah seluruh splash image sudah berakhir pada saat stateTime.
     * 
     * @param stateTime Waktu yang akan di cek
     * @return True jika sudah dan False jika belum
     */
    public boolean isImageOver(float stateTime) {
        if (stateTime >= getLastImageEndTime()) {
            return true;
        }
        return false;
    }

    /**
     * Cek apakah seluruh splash teks sudah berakhir pada saat stateTime.
     * 
     * @param stateTime Waktu yang akan di cek
     * @return True jika sudah dan False jika belum
     */
    public boolean isTextOver(float stateTime) {
        if (stateTime >= getLastImageEndTime()) {
            return true;
        }
        return false;
    }

    /**
     * Cek apakah seluruh splash image dan teks sudah berakhir pada saat stateTime.
     * 
     * @param stateTime Waktu yang akan di cek
     * @return True jika sudah dan False jika belum
     */
    public boolean isOver(float stateTime) {
        if (isImageOver(stateTime) && isTextOver(stateTime)) {
            return true;
        }
        return false;
    }

    /**
     * Mengambil gambar yang sesuai untuk waktu stateTime.
     * 
     * @param stateTime Waktu masukan
     * @return TextureRegion yang sesuai, null jika tidak ditemukan
     */
    public TextureRegion getImage(float stateTime) {
        for (int i = 0; i < imageList.size(); i++) {
            if (stateTime >= imageList.get(i).startTime && stateTime < imageList.get(i).endTime) {
                return imageList.get(i).image;
            }
        }
        return null;
    }

    /**
     * Mengambil teks yang sesuai untuk waktu stateTime.
     * 
     * @param stateTime Waktu masukan
     * @return String yang sesuai, null jika tidak ditemukan
     */
    public String getText(float stateTime) {
        for (int i = 0; i < textList.size(); i++) {
            if (stateTime >= textList.get(i).startTime && stateTime < textList.get(i).endTime) {
                return textList.get(i).text;
            }
        }
        return null;
    }

    /**
     * Mengambil teks yang sesuai untuk waktu stateTime.
     * 
     * @param stateTime Waktu masukan
     * @return String yang sesuai, null jika tidak ditemukan
     */
    public Color getTextColor(float stateTime) {
        for (int i = 0; i < textList.size(); i++) {
            if (stateTime >= textList.get(i).startTime && stateTime < textList.get(i).endTime) {
                return textList.get(i).color;
            }
        }
        return null;
    }

    /**
     * Mendapatkan nilai transparansi (alpha) dari splash gambar pada saat stateTime
     * 
     * @param stateTime Waktu masukan
     * @return Nilai alpha
     */
    public float getImageAlpha(float stateTime) {
        for (int i = 0; i < imageList.size(); i++) {
            SplashImage currentImage = imageList.get(i);
            if (stateTime >= currentImage.startTime && stateTime < currentImage.endTime) {
                if (stateTime < currentImage.startTime + currentImage.fadeInDuration) {
                    return (stateTime - currentImage.startTime) / currentImage.fadeInDuration;
                } else if (stateTime > currentImage.endTime - currentImage.fadeOutDuration) {
                    return 1 - (stateTime - (currentImage.endTime - currentImage.fadeOutDuration)) / currentImage.fadeOutDuration;
                } else {
                    return 1;
                }
            }
        }
        return 0;
    }

    /**
     * Mendapatkan nilai transparansi (alpha) dari splash teks pada saat stateTime
     * 
     * @param stateTime Waktu masukan
     * @return Nilai alpha
     */
    public float getTextAlpha(float stateTime) {
        for (int i = 0; i < textList.size(); i++) {
            SplashText currentText = textList.get(i);
            if (stateTime >= currentText.startTime && stateTime < currentText.endTime) {
                if (stateTime < currentText.startTime + currentText.fadeInDuration) {
                    return (stateTime - currentText.startTime) / currentText.fadeInDuration;
                } else if (stateTime > currentText.endTime - currentText.fadeOutDuration) {
                    return 1 - (stateTime - (currentText.endTime - currentText.fadeOutDuration)) / currentText.fadeOutDuration;
                } else {
                    return 1;
                }
            }
        }
        return 0;
    }

    /**
     * Fungsi statik untuk mendapatkan nilai alpha dari durasi fadein maupun fadeout
     * 
     * @param duration Lama waktu fading
     * @param stateTime Waktu yang akan diambil nilai alphanya
     * @param fadeIn Diisi True jika animasi fadeIn, False jika fadeOut
     * @return Nilai transparansi
     */
    public static float getAlpha(float duration, float stateTime, boolean fadeIn) {
        if (stateTime < duration) {
            return fadeIn ? stateTime / duration : 1 - (stateTime / duration);
        }
        return fadeIn ? 1 : 0;
    }
}
